package com.wpen.unit.web.filter;

import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.wpen.unit.commun.BaseResponse;
import com.wpen.unit.commun.PageRequest;
import com.wpen.unit.utils.JsonUtil;
import com.wpen.unit.web.WebVariables;

import lombok.extern.slf4j.Slf4j;

/**
 * 请求报文拦截处理
 * 
 * @author Wang Peng
 * @date 2022-12-06
 */
@Aspect
@Slf4j
public class AbstractInterceptor implements HandlerInterceptor {
    @Value("${wpen.application.log.excludes:}")
    private Set<String> logExcludes;

    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping) "
            + "|| @annotation(org.springframework.web.bind.annotation.PostMapping) "
            + "|| @annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void controllerLog() {
    }

    @Around("controllerLog()")
    public Object interception(ProceedingJoinPoint joinPoint) throws Throwable {
        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 上送参数索引号处理
        if (joinPoint instanceof MethodInvocationProceedingJoinPoint) {
            MethodInvocationProceedingJoinPoint methodJoinPoint = (MethodInvocationProceedingJoinPoint) joinPoint;
            Object[] args = methodJoinPoint.getArgs();
            for (Object arg : args) {
                if (arg instanceof PageRequest) {
                    setIndexValue(arg);
                }
            }
        }
        // 相应参数类和抛出异常处理
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Throwable throwable) {
            // @link to WebExceptionAdvice
            throw throwable;
        } finally {
            String url = request.getRequestURI();
            if (checkUrl(url) && result != null) {
                if (result instanceof BaseResponse) {
                    long causeTime = System.currentTimeMillis() - (Long) request.getAttribute(WebVariables.START_TIME);
                    ((BaseResponse) result).setExpms(causeTime);
                }
                request.setAttribute(WebVariables.RESPONSE_RESULT, result);
            }
        }
        return result;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        String url = request.getRequestURI();
        String httpMethod = request.getMethod();
        if (checkUrl(url)) {
            request.setAttribute(WebVariables.START_TIME, System.currentTimeMillis());
            String params = null;
            if (HttpMethod.POST.name().equals(httpMethod) && request instanceof RequestWrapper) {
                params = ((RequestWrapper) request).getBody();
            } else {
                params = request.getQueryString();
            }
            log.info(httpMethod + " {\"url\": \"" + url + "\", \"params\": "
                    + (params == null ? "" : params.replaceAll("\r\n", "").replaceAll("\n", "")) + "}");
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        // 方法正常执行才会进来，异常结束的不进。
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        String url = request.getRequestURI();
        String httpMethod = request.getMethod();
        if (checkUrl(url)) {
            Long causeTime = System.currentTimeMillis() - (Long) request.getAttribute(WebVariables.START_TIME);
            Object result = request.getAttribute(WebVariables.RESPONSE_RESULT);
            // 如果结果是null
            String rs = (result == null ? "" : JsonUtil.toJson(result));
            log.info(httpMethod + " {\"url\": \"" + url + "\", \"time\": " + causeTime + ", \"result\": "
                    + rs.replaceAll("\r\n", "").replaceAll("\n", "") + "}");
        }
    }

    private void setIndexValue(Object params) {
        PageRequest pageRequest = (PageRequest) params;
        Integer page = pageRequest.getPage();
        // mybatisplus 使用page，size，直接赋值给index
        pageRequest.setIndex(page);
//            Integer size = pageRequest.getSize();
//            if (size != null && size == 0) {
//                size = 10;
//                ((PageRequest) params).setSize(size);
//            }
//            // 对分页处理
//            if (page != null || size != null) {
//                if (page == null || page < 1) {
//                    page = 1;
//                }
//                pageRequest.setIndex(((page - 1) * size));
//            }
    }

    /**
     * url检查，减少代码执行量
     * 
     * @param url
     * @return
     */
    private boolean checkUrl(String url) {
        boolean cs = url.indexOf(WebVariables.API_PATH) > 0;
        if (cs) {
            for (String exclude : logExcludes) {
                if (url.indexOf(exclude) > 1) {
                    return false;
                }
            }
        }
        return cs;
    }
}
